package util

import (
	"encoding/json"
	"errors"
	"fmt"
	"hash/fnv"
	redis2 "longmen/server/config/global"
	_const "longmen/server/pkg/common/helper/const"
	string2 "longmen/server/pkg/common/helper/string"
	time2 "longmen/server/pkg/common/helper/timehelper"
	"math/rand"
	"path"
	"regexp"
	"runtime"
	"strings"
	"time"
	"unicode"

	"longmen/server/pkg/common/api_models"

	"github.com/go-playground/validator/v10"
	"github.com/go-redis/redis"
	"github.com/google/uuid"
	"github.com/mozillazg/go-pinyin"
)

func DiffArrayInt(ids []int, id int) []int {
	index := -1
	for idx := range ids {
		if ids[idx] == id {
			index = idx
			break
		}
	}
	if index >= 0 {
		result := make([]int, 0)
		result = append(result, ids[:index]...)
		result = append(result, ids[index+1:]...)
		return result
	}
	return ids
}

func ArrayDiff(array1 []string, arrayOthers ...[]string) []string {
	c := make(map[string]bool)
	for i := 0; i < len(array1); i++ {
		if _, hasKey := c[array1[i]]; hasKey {
			c[array1[i]] = true
		} else {
			c[array1[i]] = false
		}
	}
	for i := 0; i < len(arrayOthers); i++ {
		for j := 0; j < len(arrayOthers[i]); j++ {
			if _, hasKey := c[arrayOthers[i][j]]; hasKey {
				c[arrayOthers[i][j]] = true
			} else {
				c[arrayOthers[i][j]] = false
			}
		}
	}
	result := make([]string, 0)
	for k, v := range c {
		if !v {
			result = append(result, k)
		}
	}
	return result
}

// 生成订单号
func GenOrderId(action string, f int) string {
	if f == 1 {
		return fmt.Sprintf("%s%s%d", strings.ToUpper(action), time.Now().Format("060102150405000"), string2.RandInt(100000, 999999))
	}
	return fmt.Sprintf("%s%s%d", strings.ToUpper(action), time.Now().Format("060102150405"), string2.RandInt(1000, 9999))
}

// 手机端返回true，否则返回false，默认返回false,即PC端
func IsMobile(ua string) bool {
	ua = strings.ToLower(ua)
	//常见的手机端UA判断，有即默认为手机端 pad、phone关键字替代ipad，iphone,apad等
	mobile := []string{"mobile", "pad", "pod", "wap", "smartphone", "apk", "ios", "iphone", "ipod", "ipad", "android", "android", "nokia", "symbianos", "symbian", "windows phone", "phone", "linux armv71", "maui", "untrusted/1.0", "windows ce", "blackberry", "iemobile"}
	for _, m := range mobile {
		if strings.Contains(ua, m) {
			return true
		}
	}
	return false
}

// 生成订单号
func CreateOrderNo(uid int, prefix string) string {
	return prefix + I2S(uid) + time.Now().Format(time2.TIME_LAYOUT_FORMAT_2) + I2S(string2.RandInt(1000, 9999))
}

/**
 * @Author willi
 * @Description //
 * @Date 14:43 2022/9/26
 * @Param
 * @return
 **/
func CreatePaymentOrderNo(prefix string) (string, error) {
	if len(prefix) > 5 {
		return "", errors.New("前缀长度不能大于5")
	}
	initZero := "00000"
	prefix = prefix + initZero[0:5-len(prefix)]
	return strings.ToTitle(prefix) + time.Now().Format(time2.TIME_LAYOUT_FORMAT_2) + fmt.Sprintf("%05s", I2S(string2.RandInt(0, 99999))), nil

}

// 生成n个数字字母
type Size interface {
	Size() int64
}

func GetLiveType(pullUrl string) string {
	urlSlice := strings.Split(pullUrl, ".")
	switch urlSlice[len(urlSlice)-1] {
	case "m3u8":
		return "hls"
	case "mpd":
		return "dash"
	case "flv":
		return "flv"
	case "mp4":
		return "auto"
	}
	return ""
}

func GetValidateError(err error) error {
	errMsgArr := make([]string, 0)
	for _, v := range err.(validator.ValidationErrors) {
		errMsgArr = append(errMsgArr, v.Translate(_const.Trans))
	}
	return errors.New(strings.Join(errMsgArr, ","))
}

func CheckClickTime(uid, count int, limitTime time.Duration, blockTime time.Duration) (string, error) {
	fName := "CheckClickTime"
	redisKey := fmt.Sprintf("go_webapi_click_attent_anchor_%d", uid)
	val, err := redis2.GetRds().Get(redisKey).Result()
	if err == redis.Nil {
		_, err = redis2.GetRds().Incr(redisKey).Result()
		if err != nil {
			return "", fmt.Errorf("%s %s", fName, err.Error())
		}
		_, err = redis2.GetRds().Expire(redisKey, limitTime).Result()
		if err != nil {
			return "", fmt.Errorf("%s %s", fName, err.Error())
		}
		return "", nil
	}
	if err != nil {
		return "", fmt.Errorf("%s %s", fName, err.Error())
	}
	if S2I(val) >= count {
		_, err = redis2.GetRds().Expire(redisKey, blockTime).Result()
		if err != nil {
			return "", fmt.Errorf("%s %s", fName, err.Error())
		}
		return "操作过于频繁请稍后再试", fmt.Errorf("%s 操作过于频繁请稍后再试", fName)
	}
	_, err = redis2.GetRds().Incr(redisKey).Result()
	if err != nil {
		return "", fmt.Errorf("%s %s", fName, err.Error())
	}
	return "", nil
}

func RetrieveCallInfo() *_const.CallInfo {
	pc, file, line, _ := runtime.Caller(2)
	_, fileName := path.Split(file)
	parts := strings.Split(runtime.FuncForPC(pc).Name(), ".")
	pl := len(parts)
	packageName := ""
	funcName := parts[pl-1]
	if parts[pl-2][0] == '(' {
		funcName = parts[pl-2] + "." + funcName
		packageName = strings.Join(parts[0:pl-2], ".")
	} else {
		packageName = strings.Join(parts[0:pl-1], ".")
	}
	return &_const.CallInfo{
		PackageName: packageName,
		FileName:    fileName,
		FuncName:    funcName,
		Line:        line,
	}
}

/*
*
@Create July-01 2022 Enzo
*传入公会分成比例，订单总金额、各层分配方案
*返回主播要分的钱，各经理要分的钱（切片）
*各经纪人要分的钱会被记在plan里
**主播分的钱不是单纯的等于他的比例，而是总额减去其他人的所得；
**因为只精确到分，当数额小时，四舍五入可能会造成1分偏差，报表对不上
*/
func CalcCommissionListByAmount(guildShareRate float64, plan *[]api_models.ManagerRate, totalAmount int) (int, *[]api_models.ManagerRate) {
	iAnchorAmount := int(string2.Round(float64(totalAmount)*guildShareRate, 0)) //公会能分配的钱
	for i := 0; i < len(*plan); i++ {
		(*plan)[i].ShareAmount = int(string2.Round(float64(totalAmount)*(*plan)[i].Rate, 0))
		iAnchorAmount -= (*plan)[i].ShareAmount
	}
	return iAnchorAmount, plan
}
func GetCoinName(coinType int) string {
	switch coinType {
	case 1:
		return "龙钻"
	case 2:
		return "龙币"
	default:
		return ""
	}
}

func GetFundsType(typeVal int32) _const.FundsType {
	var fundsType _const.FundsType
	switch typeVal {
	case 1:
		fundsType = _const.CoinGold
	case 2:
		fundsType = _const.CoinDiamond
	default:
	}
	return fundsType
}

/*
*
Created Enzo July04 2022
结合业务，由这个方法判断一些数值是不是合法
*/
func ValidRange(keyName int, v float64) bool {
	switch keyName { //managerRate 未整理
	case _const.VALUE_MANAGER_RATE:
		if v <= 0.99 && v >= 0.01 { //[0.01, 0.99]
			return true
		}
	case _const.VALUE_GIFT_PRICE: //giftPrice
		if v >= 100 {
			return true
		}
	}

	return false //

}
func GetBetItemName(item int) string {
	if item <= 0 || item > 26 { //A~Z
		return ""
	}
	a := byte(65 - 1 + item) //1 for A
	return string(a) + "项"
}

/*
*
本方法会对不同的消费类型生成对应的动词
*/
func GetConsumeVerb(consume_type int, isProfit int) string {
	//1-消费礼物 2-鹰眼 3-货币转换 4 工会分成 5 主播分成
	//6 钱包充值 7 转到游戏 8 从游戏中提款 9 其他 10任务奖励
	//11参与竞猜 12赢得奖金 13退回订单 14撤回奖金 15邀请注册
	// 16注册vip
	var m_pay map[int]string
	var m_profit map[int]string
	if redis2.Lang.GetLang() == _const.LangChinese {
		m_pay = map[int]string{ //付款的订单
			1: "赠送", 2: "付费", 3: "转换",
			6: "充值", 7: "转到", 8: "提款", 9: "其他",
			11: "参与", 12: "收到", 14: "撤消", 15: "",
			19: "参与", 21: "扣减", 22: "消费",
		}

		m_profit = map[int]string{ //收款的订单
			2: "收到", 3: "转换", 4: "收到", 5: "收到",
			6: "充值", 7: "转到", 8: "提款", 9: "其他", 10: "得到",
			11: "", 12: "收到", 13: "退还", 14: "", 15: "获得",
			16: "收到",
			20: "收到", 21: "", 22: "", 100: "收到",
		}
	} else {
		m_pay = map[int]string{ //付款的订单
			1: "present", 2: "pay", 3: "convert",
			6: "recharge", 7: "transfer", 8: "withdrawal", 9: "other",
			11: "participate", 12: "received", 14: "cancel", 15: "",
			19: "participate", 21: "deduct", 22: "consume",
		}

		m_profit = map[int]string{ //收款的订单
			2: "received", 3: "transfer", 4: "received", 5: "received",
			6: "recharge", 7: "transfer", 8: "withdrawal", 9: "other", 10: "得到",
			11: "", 12: "received", 13: "refund", 14: "", 15: "obtain",
			16: "received",
			20: "received", 21: "", 22: "", 100: "received",
		}
	}

	if isProfit == 1 {
		if _, ok := m_profit[consume_type]; ok {
			return m_profit[consume_type]
		}
	}
	if isProfit == 0 {
		if _, ok := m_pay[consume_type]; ok {
			return m_pay[consume_type]
		}
	}
	return ""
}

func GetConsumeNoun(consume_type int) string {
	//1-消费礼物 2-鹰眼 3-货币转换 4 工会分成 5 主播分成
	//6 钱包充值 7 转到游戏 8 从游戏中提款 9 其他 10任务收入
	//11参与竞猜 12赢得奖金 13退回订单 14撤回奖金 15邀请注册
	// 16注册vip
	var m map[int]string
	if redis2.Lang.GetLang() == _const.LangChinese {
		m = map[int]string{
			1: "", 2: "", 3: "",
			4: "", 5: "",
			6: "", 7: "", 8: "", 9: "", 10: "",
			11: "消费", 12: "彩金", 13: "本金", 14: "彩金", 15: "奖励",
			16: "",
			20: "", 21: "", 100: "",
		}
	} else {
		m = map[int]string{
			1: "", 2: "", 3: "",
			4: "", 5: "",
			6: "", 7: "", 8: "", 9: "", 10: "",
			11: "consume", 12: "bonus", 13: "principal", 14: "bonus", 15: "reward",
			16: "",
			20: "", 21: "", 100: "",
		}
	}
	if _, ok := m[consume_type]; ok {
		return m[consume_type]
	}
	return ""
}

func GetConsumeName(consume_type int) string {
	//1-消费礼物 2-鹰眼 3-货币转换 4 工会分成 5 主播分成
	//6 钱包充值 7 转到游戏 8 从游戏中提款 9 其他 10任务收入
	//11参与竞猜 12赢得奖金 13退回订单 14撤回奖金',15邀请注册
	//16注册vip 17活动送 18贵族开通与续费
	//19世界杯竞猜, 20手动充值, 21手动扣减, 22世界杯竞猜,
	//23活动消费, 24活动奖励, 100充值
	var m map[int]string
	if redis2.Lang.GetLang() == _const.LangChinese {
		m = map[int]string{
			1: "礼物", 2: "有料", 3: "货币转换",
			4: "公会分成", 5: "礼物",
			6: "钱包充值", 7: "转到游戏", 8: "游戏提款", 9: "其他", 10: "任务奖励",
			11: "游戏竞猜", 12: "竞猜奖金", 13: "退回竞猜", 14: "撤回竞猜奖金", 15: "邀请好友",
			16: "注册vip", 18: "购买贵族", 19: "世界杯竞猜",
			20: "手动充值", 21: "手动扣减", 22: "商城购买",
			23: "活动消费", 24: "活动奖励", 25: "玩游戏", 100: "充值",
		}
	} else {
		m = map[int]string{
			1: "gift", 2: "substantial", 3: "currency conversion",
			4: "guild share", 5: "gift",
			6: "wallet recharge", 7: "switch to the game", 8: "game withdrawal", 9: "other", 10: "task reward",
			11: "game betting", 12: "betting winnings", 13: "refund bet", 14: "withdraw betting winnings", 15: "invite friends",
			16: "register vip", 18: "purchase nobility", 19: "World Cup betting",
			20: "manual recharge", 21: "manual deduction", 22: "store purchase",
			23: "activity expenditure", 24: "activity rewards", 25: "play games", 100: "recharge",
		}
	}
	if _, ok := m[consume_type]; ok {
		return m[consume_type]
	}
	return ""
}
func String2IntArray(str string, n int) (iArr []int) {
	iArr = make([]int, n, n)
	if len(str) == 0 {
		return iArr
	}
	_ = json.Unmarshal([]byte(str), &iArr)
	return iArr
}

func String2FloatArray(str string, n int) (fArr []float64) {
	fArr = make([]float64, n, n)
	if len(str) == 0 {
		return fArr
	}
	_ = json.Unmarshal([]byte(str), &fArr)

	return fArr
}

// todo: test
func CalcOddsListFromAmountList(AmountList *[]int, OddsList *[]int) {
	var sum int
	sum = 0
	for _, v := range *AmountList {
		sum += v
	}
	if sum != 0 {
		for i, v := range *AmountList {
			if v == 0 || v == sum { //为0的不算，和总额一样的也不算（只有一方投注）
				(*OddsList)[i] = 0
				continue
			}
			(*OddsList)[i] = int(float64(sum) / float64(v) * 100)
		}
	}
}

/**
 * @Author admin
 * @Description //汉字 返回首字母，数字与字母原字返回
 * @version: v1.8.0
 * @Date 16:52 2022/7/16
 * @Param
 * @return
 **/
func ZhToLetter(zh string) string {
	var letter string
	if !ContainsEnglish(zh) {
		// 开启多音字模式
		c := pinyin.NewArgs()
		c.Heteronym = true
		i := pinyin.Pinyin(zh, c)
		letter = strings.ToUpper(i[0][0][:1])
	} else {
		letter = zh
	}
	return letter
}

/**
 * @Author admin
 * @Description // 测试是否包含字母与数字
 * @version: v1.8.0
 * @Date 16:55 2022/7/16
 * @Param
 * @return
 **/
func ContainsEnglish(str string) bool {
	dictionary := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789"
	return strings.Contains(dictionary, str)

}

// 是否包含链接
func ContainsLink(input string) bool {
	if !checkText([]rune(input)) {
		return true
	}
	// 定义匹配链接的正则表达式
	linkPattern := `(?i)\b(?:https?://|www\.)\S+\b`

	// 编译正则表达式
	regex := regexp.MustCompile(linkPattern)

	// 使用正则表达式查找所有匹配的链接
	matches := regex.FindAllString(input, -1)

	if len(matches) > 0 {
		return true
	}

	keywords := []string{".me"}
	for _, keyword := range keywords {
		if strings.HasSuffix(input, keyword) {
			return true
		}
	}

	return false
}

/**
 * @Author admin
 * @Description //转换并统计合值
 * @version: v1.8.0
 * @Date 15:53 2022/7/18
 * @Param
 * @return
 **/
func SliceIntToInt32(list []int) ([]int32, int) {
	slice := make([]int32, 0)
	totalVal := 0
	for _, val := range list {
		slice = append(slice, int32(val))
		totalVal += val
	}
	return slice, totalVal
}

func GetUuid() string {
	return strings.ReplaceAll(uuid.New().String(), "-", "")
}

/**
 * @author Jared
 * @description int切片去重
 * @createTime 16:17 2022/10/21
 **/
func DeduplicationSlice(slice []int) []int {
	mp := make(map[int]int, len(slice))
	for _, v := range slice {
		mp[v] = 1
	}
	var newSlice []int
	for k := range mp {
		newSlice = append(newSlice, k)
	}
	return newSlice
}

func HashUid(deviceId string) int {
	h := fnv.New64a()
	h.Write([]byte(deviceId))
	return int(h.Sum64() >> 1) //根据device Id生成数字哈希同一个deviceId生成的会一样
}

func MaxMinRand(min int, max int) int {
	randomNum := rand.Intn(max-min+1) + min
	return randomNum
}

// 求两个数组相同和不同集
func FindCommonValues(arr1, arr2 []int) ([]int, []int) {
	commonValues := make([]int, 0)
	differentValues := make([]int, 0)

	// 使用 map 来存储数组1中的值，方便进行查找
	valueMap := make(map[int]bool)
	for _, num := range arr1 {
		valueMap[num] = true
	}

	// 遍历数组2，检查是否在 map 中存在，如果存在则为共同值
	for _, num := range arr2 {
		if valueMap[num] {
			commonValues = append(commonValues, num)
		} else {
			differentValues = append(differentValues, num)
		}
	}

	return commonValues, differentValues
}

// 特殊字符转换
func convertSpecialFont(text string) string {
	replacements := map[rune]rune{
		'ａ': 'a', 'ｂ': 'b', 'ｃ': 'c', 'ｄ': 'd', 'ｅ': 'e', 'ｆ': 'f', 'ｇ': 'g', 'ｈ': 'h', 'ｉ': 'i',
		'ｊ': 'j', 'ｋ': 'k', 'ｌ': 'l', 'ｍ': 'm', 'ｎ': 'n', 'ｏ': 'o', 'ｐ': 'p', 'ｑ': 'q', 'ｒ': 'r',
		'ｓ': 's', 'ｔ': 't', 'ｕ': 'u', 'ｖ': 'v', 'ｗ': 'w', 'ｘ': 'x', 'ｙ': 'y', 'ｚ': 'z',
		'Ａ': 'A', 'Ｂ': 'B', 'Ｃ': 'C', 'Ｄ': 'D', 'Ｅ': 'E', 'Ｆ': 'F', 'Ｇ': 'G', 'Ｈ': 'H', 'Ｉ': 'I',
		'Ｊ': 'J', 'Ｋ': 'K', 'Ｌ': 'L', 'Ｍ': 'M', 'Ｎ': 'N', 'Ｏ': 'O', 'Ｐ': 'P', 'Ｑ': 'Q', 'Ｒ': 'R',
		'Ｓ': 'S', 'Ｔ': 'T', 'Ｕ': 'U', 'Ｖ': 'V', 'Ｗ': 'W', 'Ｘ': 'X', 'Ｙ': 'Y', 'Ｚ': 'Z',
		'０': '0', '１': '1', '２': '2', '３': '3', '４': '4', '５': '5', '６': '6', '７': '7', '８': '8', '９': '9',
		' ': ' ', '.': '.', 'ⅿ': 'm', '𝚎': 'e',
	}

	convertedRunes := make([]rune, 0, len(text))

	for _, char := range text {
		if replacement, ok := replacements[char]; ok {
			convertedRunes = append(convertedRunes, replacement)
		} else {
			// 如果不在替换表中，则判断是否是字母或数字，是则保留，不是则替换为空格
			if unicode.IsLetter(char) || unicode.IsNumber(char) {
				convertedRunes = append(convertedRunes, char)
			} else {
				convertedRunes = append(convertedRunes, ' ')
			}
		}
	}

	return strings.Join(strings.Fields(string(convertedRunes)), "")
}

func checkText(runes []rune) bool {
	for _, r := range runes {
		if r >= 65 && r <= 90 || r >= 97 && r <= 122 { // 不在大写字母A-Z和小写字母a-z范围内
			continue
		}
		if r >= 48 && r <= 57 { // 不在数字0-9范围内
			continue
		}
		if r >= 19968 && r <= 40959 { // 不在汉字范围内
			continue
		}
		if r >= 32 && r <= 47 || r >= 58 && r <= 64 || r >= 91 && r <= 96 || r >= 123 && r <= 126 { // 不在标点符号范围内
			continue
		}
		if r >= 12289 && r <= 12319 {
			continue
		}
		if r >= 8210 && r <= 8230 || r >= 65280 && r <= 65315 || r == 120462 { //中文标点
			continue
		}
		if isEmoji(r) {
			continue
		}
		fmt.Println("str: ", string(r), "r value: ", r)
		return false
	}
	return true
}

func isEmoji(r rune) bool {
	switch {
	case r >= 0x1F600 && r <= 0x1F64F: // 表情符号
		return true
	case r >= 0x1F300 && r <= 0x1F5FF: // 各种符号和图形符号
		return true
	case r >= 0x1F680 && r <= 0x1F6FF: // 运输与地图符号
		return true
	case r >= 0x1F700 && r <= 0x1F77F: // 炼金术符号
		return true
	case r >= 0x1F780 && r <= 0x1F7FF: // 几何图形扩展
		return true
	case r >= 0x1F800 && r <= 0x1F8FF: // 补充箭头符号
		return true
	case r >= 0x1F900 && r <= 0x1F9FF: // 补充符号与象形文字
		return true
	case r >= 0x1FA70 && r <= 0x1FAFF: // 表情符号扩展区域
		return true
	case r >= 0x2600 && r <= 0x26FF: // 杂项符号
		return true
	case r >= 0x2700 && r <= 0x27BF: // 装饰符号
		return true
	case r >= 0x1F1E6 && r <= 0x1F1FF: // 区域指示符
		return true
	case r >= 0x1F900 && r <= 0x1F9FF: // 补充符号与象形文字
		return true
	default:
		return false
	}
}
